<?php
/**
 * 下载文件
 * Class FileDownLoad
 */
class FileDownLoad
{
    // 下载文件设置
    private $download_config = array();

    // 最大开启进程数量
    private $max_process_num = 10;

    // 超时秒数
    private $timeout = 10;

    // 日志文件
    private $logfile = null;

    // 保存路径
    private $filepath = null;

    //权限设置
    private $mode = 0777;


    /**
     * 初始化
     * @param  Array  $download_config   下载的文件设置
     * @param  Int    $max_process_num   最大开启的进程数量
     * @param  Int    $timeout           超时秒数
     * @param  String $filepath          文件存放路径
     * @param  String $logfile           日志文件路径
     * @param  String $mode              文件权限
     */
    public function __construct($download_config, $max_process_num = 10, $timeout = 10, $filepath='', $logfile='',$mode = '')
    {
        $this->download_config = $download_config;
        $this->max_process_num = $max_process_num;
        $this->timeout = $timeout;
        $this->filepath = __DIR__ . '/' . $filepath;
        $this->mode = $mode?$mode:$this->mode;

        // 日志文件
        if ($logfile) {
            $this->logfile = $logfile;
        } else {
            $this->logfile = dirname(__FILE__) . '/' . date('Ymd') . '.log';
        }
    }

    /**
     * 执行下载
     * @result Int
     */
    public function download()
    {

        // 已处理的数量
        $handle_num = 0;

        // 未处理完成
        while (count($this->download_config) > 0) {

            // 需要处理的大于最大进程数
            if (count($this->download_config) > $this->max_process_num) {
                $process_num = $this->max_process_num;
                // 需要处理的小于最大进程数
            } else {
                $process_num = count($this->download_config);
            }

            // 抽取指定数量进行下载
            $tmp_download_config = array_splice($this->download_config, 0, $process_num);

            // 执行下载
            $result = $this->process($tmp_download_config);

            // 记录已处理的数量
            $handle_num += count($result);

        }

        return $handle_num;

    }

    /**
     * 多进程下载文件
     * @param Array $download_config 本次下载的设置
     * @return Array
     */
    public function process($download_config)
    {

        // 文件资源
        $fp = array();

        // curl会话
        $ch = array();

        // 执行结果
        $result = array();

        //创建文件夹
        if(!is_dir($this->filepath)) mkdir($this->filepath,$this->mode);

        //二维数组不变,一维数组转二维数组
        $download_config = self::check_array($download_config);

        // 创建curl handle
        $mh = curl_multi_init();

        // 循环设定数量
        foreach ($download_config as $k => $config) {
            $ch[$k] = curl_init();
            $fp[$k] = fopen($config[1], 'a');

            curl_setopt($ch[$k], CURLOPT_URL, $config[0]);
            curl_setopt($ch[$k], CURLOPT_FILE, $fp[$k]);
            curl_setopt($ch[$k], CURLOPT_HEADER, 0);
            curl_setopt($ch[$k], CURLOPT_SSL_VERIFYHOST,false);
            curl_setopt($ch[$k], CURLOPT_SSL_VERIFYPEER,false);
            curl_setopt($ch[$k], CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch[$k], CURLOPT_USERAGENT, 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)');

            // 加入处理
            curl_multi_add_handle($mh, $ch[$k]);
        }

        $active = null;

        do {
            $mrc = curl_multi_exec($mh, $active);
        } while ($active);

        // 获取数据
        foreach ($fp as $k => $v) {
            fwrite($v, curl_multi_getcontent($ch[$k]));
        }

        // 关闭curl handle与文件资源
        foreach ($download_config as $k => $config) {
            curl_multi_remove_handle($mh, $ch[$k]);
            fclose($fp[$k]);

            // 检查是否下载成功
            if (file_exists($config[1])) {
                $result[$k] = true;
            } else {
                $result[$k] = false;
            }
        }

        curl_multi_close($mh);

        return $result;

    }

    /**
     * 判断数组
     * @param $download_config
     * @return array
     */
    private function check_array($download_config){
        $tmp = array();
        if (count($download_config) == count($download_config, 1)) {
            while(@list($key,$val) = each($download_config)) {
                $tmp[] = array($val,$this->filepath . '/' . uniqid() .'.'. explode('.',basename($val))[1]);
            }
        } else {
            foreach ($download_config as $k=>$v) {
                @list($key,$list) = $v;
                if(isset($list)&&!empty($list)){
                    $list = $this->filepath . '/' . $list;
                }else{
                    $list = $this->filepath . '/' . uniqid() .'.'. explode('.',basename($key))[1];
                }
                $tmp[] = [$key,$list];
            }
        }
        return $tmp;
    }
}
